#include "camera_video_sink.h"
#include <QDebug>

CameraVideoSink::CameraVideoSink() : m_vcm(nullptr) {
    rtc::LogMessage::SetLogToStderr(true);

}

CameraVideoSink::~CameraVideoSink() {
  Destroy();
}

bool CameraVideoSink::Init(size_t width,
                           size_t height,
                           size_t target_fps,
                           size_t capture_device_index) {
  std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> device_info(webrtc::VideoCaptureFactory::CreateDeviceInfo());

  char device_name[256];
  char unique_name[256];

  if (device_info->GetDeviceName(static_cast<uint32_t>(capture_device_index),
                                 device_name, sizeof(device_name), unique_name,
                                 sizeof(unique_name)) != 0) {
    Destroy();
    return false;
  }

  m_vcm = webrtc::VideoCaptureFactory::Create(unique_name);
  if (!m_vcm) {
    return false;
  }
  m_vcm->RegisterCaptureDataCallback(this);

  device_info->GetCapability(m_vcm->CurrentDeviceName(), 0, m_capability);
  m_capability.width = static_cast<int32_t>(width);
  m_capability.height = static_cast<int32_t>(height);
  m_capability.maxFPS = static_cast<int32_t>(target_fps);
  m_capability.videoType = webrtc::VideoType::kI420;

  if (m_vcm->StartCapture(m_capability) != 0) {
    Destroy();
    return false;
  }

  RTC_CHECK(m_vcm->CaptureStarted());
  return true;
}

CameraVideoSink* CameraVideoSink::Create(size_t width,
                                         size_t height,
                                         size_t target_fps,
                                         size_t capture_device_index) {
  std::unique_ptr<CameraVideoSink> vcm_capturer(new CameraVideoSink());
  if (!vcm_capturer->Init(width, height, target_fps, capture_device_index)) {
    RTC_LOG(LS_WARNING) << "Failed to create VcmCapturer(w = " << width
                        << ", h = " << height << ", fps = " << target_fps
                        << ")";
    return nullptr;
  }
  return vcm_capturer.release();
}

void CameraVideoSink::Destroy() {
  if (!m_vcm)
    return;

  m_vcm->StopCapture();
  m_vcm->DeRegisterCaptureDataCallback();
  // Release reference to VCM.
  m_vcm = nullptr;
}

void CameraVideoSink::OnFrame(const webrtc::VideoFrame& frame) {
    static auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::system_clock::now().time_since_epoch()).count();
    static size_t cnt = 0;

//    qDebug()<<int(frame.video_frame_buffer()->type());
    rtc::scoped_refptr<webrtc::I420BufferInterface> frameBuffer =
            frame.video_frame_buffer()->ToI420();
    cnt++;
    int width = this->m_capability.width;
    int height = this->m_capability.height;

    uint8_t *data = new uint8_t[width * height*4];
//    qDebug()<<width*height<<int(frameBuffer->GetI420()->type());
    memcpy(data,frameBuffer->GetI420()->DataY(),width*height);
    memcpy(data + width*height ,frameBuffer->GetI420()->DataU(),
           width*height/4);
    memcpy(data + width*height + width*height/4,
           frameBuffer->GetI420()->DataV(),
           width*height/4);

    m_buf.PushFirst(data);

    auto timestamp_curr = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::system_clock::now().time_since_epoch()).count();
    if(timestamp_curr - timestamp > 1000) {
        qDebug()<<timestamp;
        RTC_LOG(LS_INFO) << "FPS: " << cnt<<m_buf.Size();
        cnt = 0;
        timestamp = timestamp_curr;
    }
}


webrtc::VideoCaptureCapability CameraVideoSink::Capability()
{
    return this->m_capability;
}

uint8_t *FrameBufferList::TakeLast()
{
    std::lock_guard<std::mutex> guard(this->m_mutex);
    if(m_data.size() != 0){
        auto ret = *m_data.begin();
        m_data.pop_front();
        return ret;
    }
}

void FrameBufferList::PushFirst(uint8_t*v)
{
    std::lock_guard<std::mutex> guard(this->m_mutex);
    m_data.push_back(v);
}

uint16_t FrameBufferList::Size()
{
    std::lock_guard<std::mutex> guard(this->m_mutex);
    return m_data.size();
}


